/**
 * Created in 2012-3-9.
 */
package kit4j.jdbc.hql;

import java.util.List;
import java.util.Map;

import kit4j.jdbc.sql.SqlUtil;
import kit4j.util.lang.StringUtil;

/**
 * HQL语句构建工具类。
 * 
 * @author MiniKnife
 * 
 */
public abstract class AbstractHqlBuilder {

	private String objectName;

	/**
	 * 通过指定的参数表构建HQL查询语句。
	 * 
	 * @param params
	 *            参数表
	 * @return HQL查询语句
	 */
	public String buildHqlQueryFromParamMap(Map<String, Object> params) {
		StringBuilder hql = new StringBuilder();

		hql.append("from ");
		hql.append(getClassName());
		hql.append(" ");
		hql.append(getObjectName());
		hql.append(buildWhereClauseFromParamMap(params));

		return hql.toString();
	}

	/**
	 * @return 当前映射的对象类型的属性列表。
	 */
	public abstract List<String> getPropertyList();

	/**
	 * @return 当前映射的对象类型名称。
	 */
	public abstract String getClassName();

	/**
	 * @return 创建的HQL语句中指代当前映射的对象名称。
	 */
	public String getObjectName() {
		if (objectName == null) {
			objectName = createDefaultObjectNameFromClassName(getClassName());
		}

		return objectName;
	}

	/**
	 * 根据指定的类型名称创建一个将类型名称首字母小写的变量名。
	 * 
	 * @param className
	 *            类型名称
	 * @return 首字母小写的变量名
	 * @throws IllegalArgumentException
	 *             如果className为null或空字符串，则抛出此异常。
	 */
	public String createDefaultObjectNameFromClassName(String className)
			throws IllegalArgumentException {
		if (StringUtil.isEmpty(className)) {
			throw new IllegalArgumentException("class name is empty");
		}

		return className.substring(0, 1).toLowerCase() + className.substring(1);
	}

	/**
	 * 通过指定的约束参数表创建对应的Where子句。
	 * 
	 * @param params
	 *            参数表
	 * @return 根据参数表创建的Where子句
	 */
	protected String buildWhereClauseFromParamMap(Map<String, Object> params) {
		StringBuilder whereClause = new StringBuilder();
		List<String> propertyList = getPropertyList();

		for(String propertyName : propertyList) {
			String clause = buildConditionClause(propertyName, params);

			if (StringUtil.isNotEmpty(clause)) {
				if (whereClause.length() == 0) {
					whereClause.append(" where ");
				} else {
					whereClause.append(" and ");
				}
				whereClause.append(clause);
			}
		}

		return whereClause.toString();
	}

	/**
	 * 通过指定的属性名称和参数表创建对应的条件子句。
	 * 
	 * @param propertyName
	 *            属性名称
	 * @param params
	 *            参数表
	 * @return 用于Where子句中的条件子句，如果参数表中不存在指定的属性名称的键，则返回一个空字符串；特别的，
	 *         如果参数表中存在指定属性名称的键且对应的值为null，则返回的子句呈现为"*.propertyName is null"。
	 */
	protected String buildConditionClause(String propertyName,
			Map<String, Object> params) {
		if (!params.containsKey(propertyName)) {
			return "";
		}

		Object value = params.get(propertyName);
		StringBuilder clause = new StringBuilder();

		clause.append(buildPropertyPath(propertyName));

		if (value == null) {
			clause.append(" is null");
		} else {
			clause.append("=");
			clause.append(SqlUtil.convertValueToSqlString(value));
		}

		return clause.toString();
	}

	/**
	 * 构建指定属性的引用路径。
	 * 
	 * @param propertyName
	 *            属性名称
	 * @return 属性的引用路径，使用"."进行分隔。
	 */
	protected String buildPropertyPath(String propertyName) {
		StringBuilder path = new StringBuilder();

		path.append(getObjectName());
		path.append(".");
		path.append(propertyName);

		return path.toString();
	}
}
